/*
    日志器模块
    1. 抽象日志器基类
    2. 派生出不同的子类(同步日志器类 & 异步日志器类)
*/

#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__

// #define _GNU_SOURCE

#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp" 
#include "looper.hpp"

#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>

namespace log_sys{
    class Logger{
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string& logger_name, Log_level::Value level, 
            Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            :_loggername(logger_name)
            ,_limitlevel(level)
            ,_formatter(formatter)
            ,_sinks(sinks.begin(), sinks.end())
            {}

        const std::string & getloggername()
        {
            return _loggername;
        }

        /*完成构造日志消息对象过程并进行格式化，得到格式化后的日志消息*/
        void debug(const std::string &file, size_t line, const std::string &fmt, ...){
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            if (Log_level::Value::DEBUG < _limitlevel){
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                free(res);
                return;
            }
            // 将 ap 指针置空
            va_end(ap);
            serialize(Log_level::Value::DEBUG, file, line, res);
            free(res);
        }

        void info(const std::string &file, size_t line, const std::string &fmt, ...){
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            if (Log_level::Value::INFO < _limitlevel){
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                free(res);
                return;
            }
            // 将 ap 指针置空
            va_end(ap);
            serialize(Log_level::Value::INFO, file, line, res);
            free(res);
        }

        void warn(const std::string &file, size_t line, const std::string &fmt, ...){
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            if (Log_level::Value::WARN < _limitlevel){
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                free(res);
                return;
            }
            // 将 ap 指针置空
            va_end(ap);
            serialize(Log_level::Value::WARN, file, line, res);
            free(res);

        }

        void error(const std::string &file, size_t line, const std::string &fmt, ...){
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            if (Log_level::Value::ERROR < _limitlevel){
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                free(res);
                return;
            }
            // 将 ap 指针置空
            va_end(ap);
            serialize(Log_level::Value::ERROR, file, line, res);
            free(res);
        }

        void fatal(const std::string &file, size_t line, const std::string &fmt, ...){
            // 通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            if (Log_level::Value::FATAL < _limitlevel){
                return;
            }
            va_list ap;
            va_start(ap, fmt);
            char* res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                free(res);
                return;
            }
            // 将 ap 指针置空
            va_end(ap);
            serialize(Log_level::Value::FATAL, file, line, res);
            free(res);
        }
    protected:
        void serialize(Log_level::Value level, const std::string &file, size_t line, char* str)
        {
            // 构造 LogMsg 对象
            LogMsg msg(_loggername, file, line, str, level);

            // 通过Formatter 类对 LogMsg 进行格式化，得到格式化后的日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg);

            // 输出日志到指定位置
            log(ss.str().c_str(), ss.str().size());
        }

        /*抽象接口完成实际的落地输出 -- 不同的日志器(同步 / 异步)会有不同的消息输出位置*/
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;
        std::string _loggername;
        // 每一个需要输出日志的进程或线程都会查看日志限制等级，
        // 为了保证线程安全，将这个变量设置为atomic的
        std::atomic<Log_level::Value> _limitlevel;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class SyncLogger : public Logger{
    public:
        SyncLogger(const std::string& logger_name, Log_level::Value level, 
            log_sys::Formatter::ptr &formatter, std::vector<log_sys::LogSink::ptr> &sinks)
            // 创建一个父类的匿名对象，就相当于调用父类的构造函数，初始化以下子类中父类那一部分的成员变量
            :Logger(logger_name, level, formatter, sinks)
            {}
    protected:
        // 同步日志器，是将日志直接通过落地模块句柄进行日志输出到指定位置的操作
        void log(const char* data, size_t len){
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty()){
                return;
            }

            for (auto &sink : _sinks){
                sink->log(data, len);
            }
            
        }
    };

    class AsyncLogger : public Logger{
    public:
        AsyncLogger(const std::string& logger_name, Log_level::Value level, 
            log_sys::Formatter::ptr &formatter, std::vector<log_sys::LogSink::ptr> &sinks,
            TypeAsync _loopertype)
                // 创建一个父类的匿名对象，就相当于调用父类的构造函数，初始化以下子类中父类那一部分的成员变量
                :Logger(logger_name, level, formatter, sinks)
                ,_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), _loopertype))
            {}

        void log(const char* data, size_t len){
            _looper->push(data, len);
        }

        void realLog(Buffer& buf)
        {
            if (_sinks.empty())
            {
                return;
            }
            for(auto &sink : _sinks)
            {
                sink->log(buf.begin(), buf.readablesize());
            }
        }
    private:
        AsyncLooper::ptr _looper;
    };

    // 抽象一个日志器建造者类（完成日志器对象所需零部件的构建 & 日志器的构建），需要进行以下操作
    // 1. 设置日志器类型
    // 2. 将不同类型日志器的创建放到同一个日志器建造者类中完成
    enum class LoggerType{
        SYNC_LOGGER,
        ASYNC_LOGGER
    };

    class loggerBuilder{
    public:
        loggerBuilder()
            :_loggertype(LoggerType::SYNC_LOGGER)
            ,_limitlevel(Log_level::Value::DEBUG)
            ,_loopertype(TypeAsync::SAFE_ASYNC)
            {}

        void TypeBuilder(LoggerType type)
        {
            _loggertype = type;
        }

        void ChangeUnsafeAsyncBuilder()
        {
            _loopertype = TypeAsync::UNSAFE_ASYNC;
        }

        void NameBuilder(const std::string& name)
        {
            _loggername = name;
        }

        void LevelBuilder(Log_level::Value level)
        {
            _limitlevel = level;
        }

        void FormatBuilder(const std::string& pattern )
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }

        // 为了让日志器使用者在调用的时候可以指定日志的输出方向，可以使用如下的设计
        template<typename SinkType, typename ...Args>
        void SinkBuilder(Args && ...args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        
        virtual Logger::ptr build() = 0;

    protected:
        TypeAsync _loopertype;
        LoggerType _loggertype;
        std::string _loggername;
        Log_level::Value _limitlevel;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };
    // 派生出具体的建造者类 --- 局部日志器的建造者 & 全局的日志器建造者
    // （后面添加了全局单例管理器之后，将日志器添加全局管理）
    class LocalLoggerBuilder : public loggerBuilder{
    public:
        Logger::ptr build() override{
            assert(!_loggername.empty());
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                SinkBuilder<StdoutSink>();
            }
            if (_loggertype == LoggerType::ASYNC_LOGGER)
            {
                return std::make_shared<AsyncLogger>(_loggername, _limitlevel, _formatter, _sinks, _loopertype);
            }
            return std::make_shared<SyncLogger>(_loggername, _limitlevel, _formatter, _sinks);
        }
    };

    class LoggerManager {
    public:
        static LoggerManager& getInstance()
        {
            // 在C++11之后，针对静态局部变量，编译器在编译的层面实现了线程安全
            // 在局部静态变量没有构造完成之前，其他线程就会进入阻塞
            static LoggerManager instance;
            return instance;
        }

        void addLogger(Logger::ptr &logger)
        {
            if(hasLogger(logger->getloggername()))
            {
                return;
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->getloggername(), logger));
        }

        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            auto it =  _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }

        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            auto it =  _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;            
        }

        Logger::ptr getRootLogger()
        {
            return _rootlogger;
        }
    private:
        LoggerManager(){
            std::unique_ptr<log_sys::loggerBuilder> builder(new log_sys::LocalLoggerBuilder());
            builder->NameBuilder("root");
            _rootlogger = builder->build();
            _loggers.insert(std::make_pair("root", _rootlogger));
        }

        LoggerManager(const LoggerManager&) = delete;
        LoggerManager& operator=(const LoggerManager&) = delete;
    private:
        std::mutex _mutex;
        Logger::ptr _rootlogger; // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };

    // 设计一个全局日志器的建造者
    class GlobalLoggerBuilder : public loggerBuilder{
    public:
        Logger::ptr build() override{
            assert(!_loggername.empty());
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                SinkBuilder<StdoutSink>();
            }

            Logger::ptr logger;
            if (_loggertype == LoggerType::ASYNC_LOGGER)
            {
                logger = std::make_shared<AsyncLogger>(_loggername, _limitlevel, _formatter, _sinks, _loopertype);
            }
            else
            {
                logger = std::make_shared<SyncLogger>(_loggername, _limitlevel, _formatter, _sinks);
            }
            LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}

#endif
